/**
 * FssClient.java
 */
package fss.client;

import java.io.File;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Logger;

import fss.common.communication.DownloadRequest;
import fss.common.communication.PingRequest;
import fss.common.communication.QueryResult;
import fss.core.config.FssProperties;
import fss.core.logger.FssLogger;
import fss.remote.RemoteClient;
import fss.remote.util.RemoteFileService;
import fss.transfer.StatusType;
import fss.transfer.Transfer;
import fss.transfer.TransferId;
import fss.transfer.TransferSource;
import fss.transfer.TransferType;
import fss.transfer.TransferUtils;
import fss.util.FssUtils;
import fss.util.SerializableUtils;
import fss.util.rmi.RmiId;
import fss.util.rmi.RmiUtils;

/**
 * 
 * @author thinh
 * @deprecated DO NOT USE UNLESS YOU WANT TO REFACTOR THIS CLASS.
 */
public class FssClient implements RemoteClient, FileServiceClientUI {
    /**
     * The data directory (includes the '/').
     */
    private static final String DATA_DIR = "/data";
    /**
     * The id.
     */
    private RmiId id = null;
    /**
     * Home directory for this client.
     */
    private String homedir = null;
    /**
     * Data directory for this client (i.e. the directory where files are stored).
     */
    private String datadir = null;
    /**
     * Constructs a client with the specified identifier.
     * @param id the id.
     */
    public FssClient(RmiId id) {
        this.id = id;
        homedir = FssProperties.getInstance().getClientHomeDir(id.getName());
        datadir = homedir + DATA_DIR;
        FssUtils.createDirectory(homedir);
        FssUtils.createDirectory(datadir);
    }
    @Override
    public void update(Object observable, Object message) throws RemoteException {
        Logger logger = FssLogger.getInstance().getClientLogger(id.getName());
        if(message instanceof PingRequest) {
            PingRequest ping = (PingRequest) message;
            logger.info("Recieved PingRequest from " + ping.getSource());
        } 
        else if(message instanceof Transfer) {
            Transfer transfer = (Transfer) message;
            
            if(transfer.getId().getType() == TransferType.DOWNLOAD) {
                handleDownloadTransfer(transfer);
            } else if(transfer.getId().getType() == TransferType.UPLOAD) {
                handleUploadTransfer(transfer);
            } else {
                logger.warning("Received Transfer of uknown type " + transfer.getId().getType() + ". Not processing this message.");
            }
        }
    }
    /**
     * Get the home directory for this client.
     * @return the homedir.
     */
    public String getHomedir() {
        return homedir;
    }
    /**
     * Get the data directory for this client.
     * @return the datadir.
     */
    public String getDatadir() {
        return datadir;
    }
    @Override
    public RmiId getId() throws RemoteException {
        return id;
    }
    @Override
    public void download() {
        Logger logger = FssLogger.getInstance().getClientLogger(id.getName());
        Scanner in = new Scanner(System.in);
        DownloadRequest request = null;
        RmiId serviceId = FssUtils.getRmiId("-- Remote File Service Identifier --");
        RemoteFileService service = (RemoteFileService)RmiUtils.getRemoteObject(serviceId);
        System.out.println();
        List<QueryResult> files;
        try {
            files = service.getFileList();
            System.out.println("File(s) on " + serviceId);
            for(int i = 0; i < files.size(); i++) {
                System.out.println((i+1) + "." + files.get(i));
            }
            System.out.print("Enter the exact filename: ");
            String filename = in.nextLine();
            TransferId transferId = new TransferId(TransferType.DOWNLOAD, serviceId, id,filename, TransferSource.CLIENT);
            request = new DownloadRequest(id, transferId);
            service.processRequest(request);        
            System.out.println();
            
        } catch (RemoteException e) {
            logger.severe("Error issuing Download Request to " + serviceId + ": " + e);
        }
        
    }
//    @Override
//    public List<QueryResult> query(String param) {
//        Logger logger = FssLogger.getInstance().getClientLogger(id.getName());
//        RmiId serviceId = FssUtils.getRmiId("-- Remote Registry Identifier --");
//        RemoteFileServiceRegistry registry = (RemoteFileServiceRegistry)RmiUtils.getRemoteObject(serviceId);
//        
//        List<QueryResult> results = new ArrayList<QueryResult>();;
//        try {
//            if(registry != null) results = registry.query(param);
//        } catch (RemoteException e) {
//            logger.severe("Error querying data: " + e);
//        }
//        return results;
//    }
//    @Override
//    public void update(Observable o, Object message) {
//        update(o, message);
//    }
    @Override
    public void upload() {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void connect() {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void stop() throws RemoteException {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void start() throws RemoteException {
        // TODO Auto-generated method stub
        
    }
    private void handleUploadTransfer(Transfer transfer) {
        // TODO
    }
    /**
     * Handle a download request transfer.
     * @param transfer the transfer.
     */
    private void handleDownloadTransfer(Transfer transfer) {
        Logger logger = FssLogger.getInstance().getClientLogger(id.getName());
        // only process if this client is the intended destination
        if(transfer.getId().getDestinationId().equals(id)) {
            String persistedFilename = datadir + FssUtils.getSystemFileSeparator() + TransferUtils.getTransferFilename(transfer.getId());
            
            File transferFile = new File(persistedFilename);
            // this is the first received chunk, just serialize it
            if(!transferFile.exists()) {
                SerializableUtils.serializeObject(transfer, persistedFilename);
                logger.info("Transfer serialized to " + persistedFilename);
            } 
            // processing the transfer chunk
            else {
                Transfer previousTransfer = (Transfer) SerializableUtils.deserializeObject(persistedFilename);
                logger.info("\nPrevious Transfer: " + previousTransfer);
                logger.info("\nReceived Transfer: " + transfer);
                
                if(transfer.getStatus() == StatusType.COMPLETED) {
                    logger.info("Download transfer is complete. Removing serialized chunk " + 
                            persistedFilename + " (" + FssUtils.removeFile(persistedFilename) + ")");
                    try {
                        TransferUtils.convertTransferToFile(previousTransfer, datadir);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    // update the previous transfer chunk with the updated 
                    TransferUtils.combineTransfer(previousTransfer, transfer);

                    // serialize the file over the old file
                    SerializableUtils.serializeObject(previousTransfer, persistedFilename);
                }
            }
        }
    }
    @Override
    public List<Transfer> getIncompleteTransferList() {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void query() {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void resume(Transfer transfer) {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void clearIncompleteTransferList() {
        // TODO Auto-generated method stub
        
    }
    @Override
    public List<File> getLocalFileList() {
        // TODO Auto-generated method stub
        return null;
    }
}
